﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RPGProject.GameWorld;
using RPGProject.GameWorld.GameObjects;
using RPGProject.IOBuffers;
using RPGProject.Data_Structures;
using Microsoft.Xna.Framework.Input;
namespace RPGProject.LoopSystem
{
    /// <summary>
    /// Takes care of all the player based interactions with the game.
    /// </summary>
    class PlayerLoop : Loop
    {
        // Tells the loop what pressing a direction will do.
        private bool moving;
        private bool attacking;
        // A objects the loop needs to complete its various tasks.
        private Visuals visuals;
        private World world;
        private Player player;
        private Constants c = Constants.GetInstance();
        /// <summary>
        /// Constructs a PlayerLoop from the specified parameters.
        /// </summary>
        /// <param name="visuals"></param>
        /// <param name="loopManager"></param>
        /// <param name="world"></param>
        public PlayerLoop(Visuals visuals, LoopManager loopManager, World world)
            : base (loopManager)
        {
            this.visuals = visuals;
            this.loopManager = loopManager;
            this.world = world;
            this.player = (Player)world["player"];
            this.moving = true;
            this.attacking = false;
        }
        /// <summary>
        /// Runs through input and stuff once.
        /// </summary>
        /// <returns></returns>
        public override FuncType RunOnce()
        {
            bool actionTaken = false;
            // Set the delay to 0.
            this.Delay = 0;
            // If the player has no actionpoints it is his first turn in a while, so reset them.
            if ((int)this.world["actionPoint"] <= 0)
            {
                this.world["actionPoint"] = this.c["Player.ActionPoints"];
            }

            String parameter = "";
            int xmod = 0;
            int ymod = 0;
            // Create a set from the keys pressed.
            Set<Keys> keysPressed = new Set<Keys>(this.loopManager.KeyState.GetPressedKeys());

            
            // shows the log
            if (keysPressed[Keys.L])
            {
                this.visuals.ToShow = VisualType.LOG;
                this.loopManager.AddFunc(FuncType.PRIORITY_TO_FRONT, this.visuals);
            }
            // shows the help screen
            if (keysPressed[Keys.H])
            {

                this.visuals.ToShow = VisualType.HELP;
                this.loopManager.AddFunc(FuncType.PRIORITY_TO_FRONT, this.visuals);
            }
            // shows the opening screen
            if (keysPressed[Keys.O])
            {
                this.visuals.ToShow = VisualType.OPEN;
                this.loopManager.AddFunc(FuncType.PRIORITY_TO_FRONT, this.visuals);
            }
            // quits the game
            if (keysPressed[Keys.Q] || keysPressed[Keys.Escape])
            {
                this.loopManager.ClearAllFuncs();
                this.visuals.ToShow = VisualType.LOSE;
                this.loopManager.AddFunc(FuncType.PRIORITY_TO_FRONT, this.visuals);
                return FuncType.REMOVE_THIS;
            }
            // sets the current action to moving, or moves
            if ((keysPressed[Keys.M] || (!this.attacking && this.moving)) && !actionTaken)
            {
                ConvertDirToInt(keysPressed, ref xmod, ref ymod);
                if (xmod == 0 && ymod == 0)
                {
                    this.moving = true;
                    this.attacking = false;
                }
                else
                {
                    GameObjectEvent moveEvent = this.player.GetMoveEvent();
                    moveEvent["xmod"] = xmod;
                    moveEvent["ymod"] = ymod;
                    this.world.Listen(moveEvent);
                    this.world["actionPoint"] = (int)this.world["actionPoint"] - 1;
                    this.moving = true;
                    // set delay to 100 to prevent using to action points from one button press
                    this.Delay = 100;
                    actionTaken = true;

                }
            }
            // if pressing G begin trying to attack
            if ((keysPressed[Keys.G] || (this.attacking && !this.moving)) && !actionTaken)
            {
                ConvertDirToInt(keysPressed, ref xmod, ref ymod);
                if (xmod == 0 && ymod == 0)
                {
                    this.attacking = true;
                    this.moving = false;
                }
                else
                {
                    char angle;
                    // gives a string of the direction
                    switch (ymod)
                    {
                        case 1:
                            parameter = "down";
                            break;
                        case -1:
                            parameter = "up";
                            break;
                        default:
                            parameter = "";
                            break;
                    } 
                    switch (xmod)
                    {
                        case 1:
                            parameter += "right";
                            break;
                        case -1:
                            parameter += "left";
                            break;
                        default:
                            parameter += "";
                            break;
                    }
                    // changes the bullet to the proper direction
                    switch (parameter)
                    {
                        case "left":
                            angle = '<';
                            break;
                        case "right":
                            angle = '>';
                            break;
                        case "up":
                            angle = '^';
                            break;
                        case "down":
                            angle = 'v';
                            break;
                        case "downleft":
                            angle = '[';
                            break;
                        case "upright":
                            angle = '/';
                            break;
                        case "downright":
                            angle = ']';
                            break;
                        case "upleft":
                            angle = '\\';
                            break;
                        default:
                            angle = '@';
                            break;
                    }
                    // Creates the bullet and sends it to the front of the loop
                    Projectile bullet = new Projectile((int)this.player["x"], (int)this.player["y"], angle, xmod, ymod, this.c["Player.RangedDamage"], this.c["Player.Range"], "a bullet", this.player, this.world);
                    bullet.Init();
                    this.loopManager.AddFunc(FuncType.PRIORITY_TO_FRONT, new ProjectileLooper(bullet, this.loopManager));
                    this.world["actionPoint"] = (int)this.world["actionPoint"] - 1;
                    this.attacking = false;
                    this.moving = true;
                    // set delay to 100 to prevent using to action points from one button press
                    this.Delay = 100;
                    actionTaken = true;
                }
            }
            // check to see if the player has spent up his turn
            if ((int)this.world["actionPoint"] <= 0)
                return FuncType.ADD_TO_END;
            else
                return FuncType.REPEAT;
        }
        /// <summary>
        /// Turns a set of keys into a x and y vector.
        /// </summary>
        /// <param name="keys"></param>
        /// <param name="xmod"></param>
        /// <param name="ymod"></param>
        private void ConvertDirToInt(Set<Keys> keys, ref int xmod, ref int ymod)
        {
            xmod = 0;
            ymod = 0;
            if (keys[Keys.Up] || keys[Keys.W] || keys[Keys.NumPad8] || keys[Keys.NumPad7] || keys[Keys.NumPad9])
            {
                ymod = -1;
            }
            else if (keys[Keys.Down] || keys[Keys.S] || keys[Keys.NumPad2] || keys[Keys.NumPad1] || keys[Keys.NumPad3])
            {
                ymod = 1;
            }
            if (keys[Keys.Left] || keys[Keys.A] || keys[Keys.NumPad4] || keys[Keys.NumPad7] || keys[Keys.NumPad1])
            {
                xmod = -1;
            }
            else if (keys[Keys.Right] || keys[Keys.D] || keys[Keys.NumPad6] || keys[Keys.NumPad3] || keys[Keys.NumPad9])
            {
                xmod = 1;
            }
        }



        public override string ToString()
        {
            return "Player";
        }
    }
}
